package com.googlecode.mailnet.netmodel;

import com.googlecode.mailnet.math.distribution.Distribution;

import java.io.Serializable;

/**
 * Single message flow from one node into another.
 * 
 * @author Gleb Rybakov
 * @author Iskander Akishev
 */
public class MessageFlow extends NetworkItem implements Serializable {

	public Node getSource() {
		return route == null ? null : route.getSource();
	}

	public Node getDestination() {
		return route == null ? null : route.getDestination();
	}

	public Route getRoute() {
		return route;
	}

	public void setRoute(Link[] links) {
		checkBeforeModifications();
		clearRoute();
		route = new Route(this, links);
	}

	public Distribution getMessageSizeDistribution() {
		return messageSizeDistribution;
	}

	public void setMessageSizeDistribution(Distribution messageSizeDistribution) {
		checkBeforeModifications();
		this.messageSizeDistribution = messageSizeDistribution;
	}

	public Distribution getMessagesAmountDistribution() {
		return messagesAmountDistribution;
	}

	public void setMessagesAmountDistribution(Distribution messagesAmountDistribution) {
		checkBeforeModifications();
		this.messagesAmountDistribution = messagesAmountDistribution;
	}

	public int getMessagesPriority() {
		return messagesPriority;
	}

	public void setMessagesPriority(int messagesPriority) {
		checkBeforeModifications();
		if (messagesPriority < 0 ||
			messagesPriority >= networkConfiguration.getQueueingConfiguration().getQueuesNumber())
		{
			throw new IllegalArgumentException("Illegal messages priority: " + messagesPriority);
		}
		this.messagesPriority = messagesPriority;
	}

	public void remove() {
		if (markRemoved()) {
			return;
		}
		boolean result = networkConfiguration.flows.remove(this);
		assert result;

		clearRoute();
	}

	// ==================== Implementation ====================

	private Distribution messageSizeDistribution;
	private Distribution messagesAmountDistribution;
	private int messagesPriority;
	Route route;

	void clearRoute() {
		if (this.route != null) {
			this.route.remove();
		}
	}

	MessageFlow(NetworkConfiguration networkConfiguration) {
		super(networkConfiguration);
		networkConfiguration.flows.add(this);
	}

	void validate() throws IllegalStateException {
		assert !isRemoved();
		if (messageSizeDistribution == null) {
			throw new IllegalStateException("Messages size distribution undefined for flow \"" + this + "\"");
		}
		if (messagesAmountDistribution == null) {
			throw new IllegalStateException("Messags amount distribution undefined for flow \"" + this + "\"");
		}
		if (route == null) {
			throw new IllegalStateException("Route undefined for flow \"" + this + "\"");
		}
	}
}
